package cn.kk.fluidcells.cells.keyboard.internal;

import cn.kk.fluidcells.cells.keyboard.KeyCode;
import cn.kk.fluidcells.cells.keyboard.KeyEvent;
import cn.kk.fluidcells.cells.keyboard.KeyLocation;

import com.sun.jna.platform.win32.WinDef.LRESULT;
import com.sun.jna.platform.win32.WinDef.WPARAM;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.platform.win32.WinUser.KBDLLHOOKSTRUCT;
import com.sun.jna.platform.win32.WinUser.LowLevelKeyboardProc;

public class DefaultLowLevelKeyboardProc implements LowLevelKeyboardProc {

    @Override
    public LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT lParam) {
        final int rawCode = lParam.vkCode;
        final long evtTime = lParam.time;

        if (!KeyboardHook.isModifierKey(rawCode)) {
            final int modifiers = KeyboardHook.getModifiers(rawCode);

            switch (wParam.intValue()) {
                case WinUser.WM_KEYDOWN:
                case WinUser.WM_SYSKEYDOWN:
                    // System.out.println("KEYDOWN: time=" + lParam.time + ", scan=" + lParam.scanCode + ", vk="
                    // + lParam.vkCode);

                    final int modDown = KeyboardHelper.getEventMask(modifiers);
                    final KeyCode keyCodeDown = KeyboardHelper.getKeyCode(rawCode);
                    final KeyLocation keyLocationDown = KeyboardHelper.getKeyLocation(rawCode);
                    char text = KeyEvent.CHAR_UNDEFINED;

                    final byte[] keyMap = new byte[256];
                    final char[] keyTxt = new char[10];

                    User32.INSTANCE.GetKeyState(0);
                    if (User32.INSTANCE.GetKeyboardState(keyMap)) {
                        // TODO check toUnicode
                        if (User32.INSTANCE.ToUnicodeEx(rawCode, lParam.scanCode, keyMap, keyTxt, keyTxt.length, 0,
                                User32.INSTANCE.GetKeyboardLayout(0)) == 1) {
                            // System.err.println(Arrays.toString(keyTxt));
                            text = keyTxt[0];
                            // System.out.println("UNICODE: " + evtUnicode);
                            // TODO fire
                        }
                    }

                    final KeyEvent evtKeyCode = new KeyEvent(this, evtTime, modDown, rawCode, keyCodeDown, text,
                            keyLocationDown);
                    System.out.println("KEYDOWN: " + evtKeyCode);
                    // TODO fire

                    break;
                case WinUser.WM_KEYUP:
                case WinUser.WM_SYSKEYUP:
                    final int modUp = KeyboardHelper.getEventMask(modifiers);
                    final KeyCode keyCodeUp = KeyboardHelper.getKeyCode(rawCode);
                    final KeyLocation keyLocationUp = KeyboardHelper.getKeyLocation(rawCode);
                    final KeyEvent evtKeyCodeUp = new KeyEvent(this, evtTime, modUp, rawCode, keyCodeUp,
                            KeyEvent.CHAR_UNDEFINED, keyLocationUp);

                    System.out.println("KEYUP: " + evtKeyCodeUp);
                    break;
            }
        }
        return User32.INSTANCE.CallNextHookEx(KeyboardHook.keyboardHook, nCode, wParam, lParam.getPointer());
    }
}
